package com.mrd.gtimp.business.service;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.transaction.Transactional;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.mrd.base.BaseBiz;
import com.mrd.exception.SaveException;
import com.mrd.framework.config.web.json.Result;
import com.mrd.gtimp.business.entity.Commodity;
import com.mrd.gtimp.business.entity.CommodityModel;
import com.mrd.gtimp.business.entity.Contacter;
import com.mrd.gtimp.business.entity.ContacterModel;
import com.mrd.gtimp.business.entity.Declaration;
import com.mrd.gtimp.business.entity.DeclarationModel;
import com.mrd.gtimp.business.entity.SuiFuDan;
import com.mrd.gtimp.business.entity.SuiFuDanModel;
import com.mrd.gtimp.business.repository.CommodityModelDao;
import com.mrd.gtimp.business.repository.DeclarationModelDao;
import com.mrd.gtimp.business.repository.SuiFuDanModelDao;
import com.mrd.gtimp.order.entity.DeclaContainer;
import com.mrd.gtimp.order.entity.DeclaContainerModel;
import com.mrd.gtimp.order.repository.DeclaContainerModelDao;
import com.mrd.spring.repository.BaseRepository;
import com.mrd.util.LoginUtil;

@Service
public class DeclarationModelBiz extends BaseBiz<DeclarationModel> {

  private static final Logger logger = Logger.getLogger(DeclarationModel.class);

  @Resource
  private ContacterModelBiz contacterModelBiz;
  @Resource
  private CommodityModelBiz commodityModelBiz;
  @Resource
  private CommodityModelDao commodityModelDao;
  @Resource
  private DeclarationModelInformBiz declarationModelInformBiz;
  @Resource
  private SuiFuDanModelBiz suifuModelBiz;
  @Resource
  private SuiFuDanModelDao suiFuDanModelDao;
  @Resource
  private DeclarationModelDao declarationModelDao;
  @Resource
  private DeclaContainerModelDao declaContainerModelDao;
  @Resource
  private SuiFuDanBiz suiFuDanBiz;
  @Resource
  private DeclarationBiz declarationBiz;

  @Resource
  // 该处指定注入BaseRepository的dao对象
  @Qualifier("declarationModelDao")
  public void setBaseRepository(BaseRepository<DeclarationModel, String> baseRepository) {
    super.baseRepository = baseRepository;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.mrd.gtimp.business.biz.BaseBusinessBiz#saveBusiness(com.mrd.gtimp.business.pojo.
   * BaseBusiness )
   */

  public void saveBusiness(DeclarationModel declarationModel, List<String> properties)
      throws Exception {
    if (null != declarationModel && null != declarationModel.getSupCompany()
        && StringUtils.isNotEmpty(declarationModel.getSupCompany().getId())) {
      contacterModelBiz.saveConcater(declarationModel.getShipper(), declarationModel.getCustomer(),
          declarationModel.getCreator());
      if (StringUtils.isEmpty(declarationModel.getId())) {
        declarationModel.setId(null);
        saveOrupdateEntity(declarationModel);
      } else {
        updateEntity(declarationModel, properties);
      }
      if (null != declarationModel.getCommodities()) {
        for (CommodityModel commodityModel : declarationModel.getCommodities()) {
          if (StringUtils.isEmpty(commodityModel.getId())) {
            commodityModel.setId(null);
          }
          if (null == commodityModel.getDeclaration()) {
            commodityModel.setDeclaration(declarationModel);
          }
          commodityModelBiz.saveOrupdateEntity(commodityModel);
        }
      }
      if (null != declarationModel.getSuiFuDans()) {
        for (SuiFuDanModel sfd : declarationModel.getSuiFuDans()) {
          if (StringUtils.isEmpty(sfd.getId())) {
            sfd.setId(null);
          }
          if (null == sfd.getDeclaration()) {
            sfd.setDeclaration(declarationModel);
          }
          suifuModelBiz.saveOrupdateEntity(sfd);
        }
      }
      if (declarationModel.getDeclarationInform() != null) {
        if (StringUtils.isEmpty(declarationModel.getDeclarationInform().getId())) {
          declarationModel.getDeclarationInform().setId(null);
        }
        if (null == declarationModel.getDeclarationInform().getDeclaration()) {
          declarationModel.getDeclarationInform().setDeclaration(declarationModel);
        }
        declarationModelInformBiz.saveOrupdateEntity(declarationModel.getDeclarationInform());
      }
    }
  }

  /**
   * 查询模板对象并转成报关单对象
   * 
   * @param bizId 模板ID
   * @param bizType 模板类型<br/>
   *        \t all：拖车、货代、报关, C：拖车, D：货代, F：报关
   * @return 报关单对象
   */
  public Declaration queryModelAndConvertToDeclaration(String bizId, String bizType) {
    long now;
    Declaration declaration = null;
    if (StringUtils.isNoneEmpty(bizId)) {
      // declaration = new Declaration();
      DeclarationModel model = null;
      now = System.currentTimeMillis();
      // if("all".equals(bizType)){
      // model = declarationModelDao.findByBusinessId(bizId);
      // }else{
      // model = declarationModelDao.findByBusinessIdAndType(bizId, bizType);
      // }
      model = findOneModel(bizId);
      System.err.println("查询耗时：" + (System.currentTimeMillis() - now) + "毫秒");
      if (model == null) {
        System.err.println("businessId:" + bizId + "没有找到对应的模板");
      }
      // declaration = gtimp_2_0_modelCopy(model); //手动copy
      now = System.currentTimeMillis();
      declaration = beanUtilsCopy(model); // 使用beanUtils进行copy
      System.err.println("复制耗时：" + (System.currentTimeMillis() - now) + "毫秒");
    }
    return declaration;
  }

  /**
   * 拆分缓存级访问模板数据（han）
   * 
   * @author han
   * @param bizId
   * @return
   */
  @Cacheable(value = "declarationModel", key = "#bizId + '_model'")
  public DeclarationModel findOneModel(String bizId) {
    DeclarationModel declarationModel = baseRepository.findOne(bizId);
    return declarationModel;
  }

  /**
   * 手动copy
   * 
   * @param model 报关单模板
   * @return 报关单对象
   */
  private Declaration gtimp_2_0_modelCopy(DeclarationModel model) {
    Declaration declaration = new Declaration();
    /*
     * gtimp 3.0 begin
     */
    // declaration.setUnityNo();
    // declaration.setDeclareState(Declaration.DeclarationBusinessState.DRAFT_STATE);
    // declaration.setCompany_co(model.getCompany_co());
    // declaration.setCompanyName(model.getCompany_name());
    // declaration.setDeclarUp();
    /*
     * gtimp 3.0 end
     */
    declaration.setSno(model.getSno());
    declaration.setBl_no(model.getBl_no());
    declaration.setFahuo_company_co(model.getFahuo_company_co());
    declaration.setTransport_na(model.getTransport_na());
    declaration.setVoyage_no(model.getVoyage_no());
    declaration.setArrived_country(model.getArrived_country());
    declaration.setArrived_country_code(model.getArrived_country_code());
    declaration.setArrived_port(model.getArrived_port());
    declaration.setArrived_port_code(model.getArrived_port_code());
    declaration.setGoods_addr(model.getGoods_addr());
    declaration.setGoods_addr_code(model.getGoods_addr_code());
    declaration.setOther_goods_addr(model.getOther_goods_addr());
    declaration.setApproval_no(model.getApproval_no());
    declaration.setDeal_mode(model.getDeal_mode());
    declaration.setGoods_count(model.getGoods_count());
    declaration.setGoods_package(model.getGoods_package());
    declaration.setNet_weight(model.getNet_weight());
    declaration.setRemark(model.getRemark());
    declaration.setTrade_mode(model.getTrade_mode());
    declaration.setCompany_name(model.getCompany_name());
    declaration.setTransport_mode(model.getTransport_mode());
    declaration.setFahuo_company_name(model.getFahuo_company_name());
    declaration.setLevymode(model.getLevymode());
    declaration.setLevymode_code(model.getLevymode_code());
    declaration.setLc_type(model.getLc_type());
    declaration.setContract_no(model.getContract_no());
    declaration.setGross_weight(model.getGross_weight());
    declaration.setCustoms_type(model.getCustoms_type());
    declaration.setRecord_id(model.getRecord_id());
    declaration.setExport_date(model.getExport_date());
    declaration.setReport_date(null);
    declaration.setProduce_factory(model.getProduce_factory());
    declaration.setShenbao_company_co(model.getShenbao_company_co());
    declaration.setShenbao_company_name(model.getShenbao_company_name());
    declaration.setFreight1(model.getFreight1());
    declaration.setFreight2(model.getFreight2());
    declaration.setFreight3(model.getFreight3());
    declaration.setPremium1(model.getPremium1());
    declaration.setPremium2(model.getPremium2());
    declaration.setPremium3(model.getPremium3());
    declaration.setPremium1(model.getPremium1());
    declaration.setPremium2(model.getPremium2());
    declaration.setPremium3(model.getPremium3());
    declaration.setOtherfee1(model.getOtherfee1());
    declaration.setOtherfee2(model.getOtherfee2());
    declaration.setOtherfee3(model.getOtherfee3());
    declaration.setRe_manifest(model.getRe_manifest());
    declaration.setRe_record_id(model.getRe_record_id());
    declaration.setRe_jianguan(model.getRe_jianguan());
    declaration.setRe_yard_id(model.getRe_yard_id());
    declaration.setExport_port(model.getExport_port());
    declaration.setExport_port_code(model.getArrived_port_code());
    declaration.setTex_company(model.getTex_company());
    declaration.setLicense_no(model.getLicense_no());
    declaration.setSuifudan(model.getSuifudan());
    declaration.setShip_name(model.getShip_name());
    declaration.setState(Declaration.DeclarationBusinessState.DRAFT_STATE);
    List<CommodityModel> coomoModels = model.getCommodities();
    List<Commodity> commos = new ArrayList<>();
    for (CommodityModel commoModel : coomoModels) {
      Commodity commo = new Commodity();
      commo.setContainer_no(commoModel.getContainer_no());
      commo.setPackinglist_remark(commoModel.getPackinglist_remark());
      commos.add(commo);
    }
    declaration.setCommodities(commos);

    declaration.setArrived_country(model.getArrived_country());
    return declaration;
  }

  /**
   * 使用beanUtils进行copy 需要注意的是DeclarationyuDeclarationModel的属性有些不一致，需要特殊处理
   * 
   * @param model 报关单模板对象
   * @return 报关单对象
   */
  private Declaration beanUtilsCopy(DeclarationModel model) {
    Declaration declaration = new Declaration();
    if (model == null) {
      return declaration;
    }
    try {
      // 复制前的准备
      List<CommodityModel> coomoModels = model.getCommodities();
      List<SuiFuDanModel> sfdModels = model.getSuiFuDans();
      List<DeclaContainerModel> containerModels = model.getDeclaContainers();
      ContacterModel shipperModel = model.getShipper();
      model.setCommodities(null);
      model.setSuiFuDans(null);
      model.setShipper(null);
      model.setDeclaContainers(null);

      // 开始复制主要属性
      BeanUtils.copyProperties(declaration, model);

      // 准备复制自定义对象
      List<Commodity> commos = new ArrayList<>();
      List<SuiFuDan> sfds = new ArrayList<>();
      Contacter shipper = new Contacter();
      List<DeclaContainer> containers = new ArrayList();
      // 开始复制
      if (CollectionUtils.isNotEmpty(coomoModels)) {
        for (CommodityModel coomoModel : coomoModels) {
          String mid = coomoModel.getId();
          DeclarationModel md = coomoModel.getDeclaration();
          coomoModel.setId(null);
          coomoModel.setDeclaration(null);
          Commodity commo = new Commodity();
          BeanUtils.copyProperties(commo, coomoModel);
          coomoModel.setId(mid);
          coomoModel.setDeclaration(md);
          commos.add(commo);
        }
      }
      if (CollectionUtils.isNotEmpty(sfdModels)) {
        for (SuiFuDanModel sfdModel : sfdModels) {
          String mid = sfdModel.getId();
          DeclarationModel md = sfdModel.getDeclaration();
          sfdModel.setId(null);
          sfdModel.setDeclaration(null);
          SuiFuDan sfd = new SuiFuDan();
          BeanUtils.copyProperties(sfd, sfdModel);
          sfdModel.setId(mid);
          sfdModel.setDeclaration(md);
          sfds.add(sfd);
        }
      }
      if (model.getShipper() != null) {
        String mid = shipperModel.getId();
        shipperModel.setId(null);
        BeanUtils.copyProperties(shipper, shipperModel);
        shipperModel.setId(mid);
      }
      if (CollectionUtils.isNotEmpty(containerModels)) {
        for (DeclaContainerModel dcModel : containerModels) {
          String mid = dcModel.getId();
          DeclarationModel md = dcModel.getDeclaration();
          dcModel.setId(null);
          dcModel.setDeclaration(null);
          DeclaContainer dc = new DeclaContainer();
          BeanUtils.copyProperties(dc, dcModel);
          dcModel.setId(mid);
          dcModel.setDeclaration(md);
          containers.add(dc);
        }
      }
      // 补回模板数据
      model.setCommodities(coomoModels);
      model.setSuiFuDans(sfdModels);
      model.setShipper(shipperModel);
      model.setDeclaContainers(containerModels);

      // 特殊属性数据填充
      declaration.setCommodities(commos);
      declaration.setSuiFuDans(sfds);
      declaration.setDeclaContainers(containers);
      declaration.setShipper(shipper);
      // 草稿状态
      declaration.setState(Declaration.DeclarationBusinessState.DRAFT_STATE);
      // ID置空
      declaration.setId(null);

    } catch (InvocationTargetException | IllegalAccessException e) {
      System.err.println("copy exception!!!!");
      e.printStackTrace();
    }
    return declaration;
  }

  @Transactional
  public Result saveAsModelV20(String id, String modelName) throws Exception {
    Declaration declaration = declarationBiz.findEntityById(id);
    Declaration beCopy = new Declaration();
    BeanUtils.copyProperties(beCopy, declaration);
    beCopy.setRejectContents(null);
    saveAsModel(beCopy, modelName, "D", "","");
    return null;
  }

  /**
   * 将报关单保存为模板
   * 
   * @param declaration 报关单
   * @param modelName 模板名称
   * @param modelType 模板类型
   */
  @Transactional
  public void saveAsModel(Declaration declaration, String modelName, String modelType,
      String isTongguanYth,String isAgent) throws SaveException {
    DeclarationModel model = new DeclarationModel();
    if (declaration == null) {
      return;
    }
    try {
      // 复制前的准备
      List<Commodity> cmmos = declaration.getCommodities();
      List<SuiFuDan> sfds = declaration.getSuiFuDans();
      List<DeclaContainer> containers = declaration.getDeclaContainers();

      declaration.setCommodities(null);
      declaration.setSuiFuDans(null);
      declaration.setShipper(null);
      declaration.setDeclaContainers(null);

      declaration.setUnityNo(null);
      declaration.setDeclareState(null);
      declaration.setSno(null);
      declaration.setRecord_id(null);
      declaration.setEnter_page(isAgent);
      // 开始复制主要属性
      BeanUtils.copyProperties(model, declaration);
      // 草稿状态
      model.setState(Declaration.DeclarationBusinessState.DRAFT_STATE);

      model.setSave_model_person(LoginUtil.getLoginUser());
      model.setSave_model_time(new Date());
      model.setModel_name(modelName);
      model.setCustomer(LoginUtil.getLoginUser().getCompany());
      model.setType(modelType);
      model.setId(null);
      model.setIsTongguanYth(isTongguanYth);
      model.setEnter_page(isAgent);
      // 保存
      declarationModelDao.save(model);
      String modelId = model.getId();
      System.out.println(modelId);

      // 准备复制自定义对象
      List<CommodityModel> commoModels = new ArrayList<>();
      List<SuiFuDanModel> sfdModels = new ArrayList<>();
      List<DeclaContainerModel> containerModels = new ArrayList<>();
      DeclarationModel model1 = new DeclarationModel();
      model1.setId(modelId);
      System.out.println(model1);
      // 复制并保存其他
      if (CollectionUtils.isNotEmpty(cmmos)) {
        for (Commodity cmmo : cmmos) {
          Commodity commodity = new Commodity();
          BeanUtils.copyProperties(commodity, cmmo);
          commodity.setId(null);
          commodity.setDeclaration(null);
          CommodityModel commoModel = new CommodityModel();
          BeanUtils.copyProperties(commoModel, commodity);
          commoModel.setDeclaration(model1);
          commoModels.add(commoModel);
        }
        commodityModelDao.save(commoModels);
      }
      if (CollectionUtils.isNotEmpty(sfds)) {
        for (SuiFuDan sfd : sfds) {
          SuiFuDan suiFuDan = new SuiFuDan();
          BeanUtils.copyProperties(suiFuDan, sfd);
          suiFuDan.setId(null);
          suiFuDan.setDeclaration(null);
          SuiFuDanModel sfdModel = new SuiFuDanModel();
          BeanUtils.copyProperties(sfdModel, suiFuDan);
          sfdModel.setDeclaration(model1);
          sfdModels.add(sfdModel);
        }
        suiFuDanModelDao.save(sfdModels);
      }

      if (CollectionUtils.isNotEmpty(containers)) {
        for (DeclaContainer dc : containers) {
          DeclaContainer container = new DeclaContainer();
          BeanUtils.copyProperties(container, dc);
          container.setId(null);
          container.setDeclaration(null);
          DeclaContainerModel dcModel = new DeclaContainerModel();
          BeanUtils.copyProperties(dcModel, container);
          dcModel.setDeclaration(model1);
          containerModels.add(dcModel);
        }
        declaContainerModelDao.save(containerModels);
      }

    } catch (Exception e) {
      String error = "保存为模板操作失败， 报关单id:{" + declaration.getId() + "}";
      logger.error(error);
      throw new SaveException(error);
    }
  }

  /**
   * 检查模板名称是否可用，即名称不重复
   * 
   * @param modelName 模板名称
   * @param id 模板ID， 在修改模板是需要提供ID查能判断名称是否可用
   * @return 结果 true 不重复/false 重复
   */
  public boolean validModelName(String modelName, String id) {
    if (StringUtils.isEmpty(id)) {
      return declarationModelDao.countByModel_name(modelName) > 0;
    } else {
      DeclarationModel model = declarationModelDao.findByModel_name(modelName);
      if (model == null) {
        return true;
      } else if (id.equals(model.getId())) {
        return true;
      }
    }
    return false;
  }

  /**
   * 优化 删除模板数据，同时删除缓存数据
   * 
   * @author han
   * @param declarationModel
   */
  @CacheEvict(value = "declarationModel", key = "#declarationModel.id + '_model'")
  public void deleteModelBiz(DeclarationModel declarationModel) {
    declarationModelDao.delete(declarationModel);
  }
}
